#include <iostream>
#include <limits>

#include <QString>
#include <QtTest>

#include <math/MSc_Matrix.h>

////////////////////////////////////////////////////////////////////////////////

using namespace std;

////////////////////////////////////////////////////////////////////////////////

class MSc_MatrixTest : public QObject
{
    Q_OBJECT

public:

    MSc_MatrixTest();

private Q_SLOTS:

    void testConstructor();

    void testIsValid();

    void testGetArray();

    void testGetItem();

    void testSetArray();

    void testSetItem();

    void testToString();

    void testOperatorAccess();
    void testOperatorAssign();
    void testOperatorAddition();
    void testOperatorSubstraction();
    void testOperatorMultiplication();
    void testOperatorDivision();
    void testOperatorUnaryAddition();
    void testOperatorUnarySubstraction();
    void testOperatorUnaryMultiplication();
    void testOperatorUnaryDivision();
    void testOperatorEquality();
    void testOperatorInequality();
};

////////////////////////////////////////////////////////////////////////////////

MSc_MatrixTest::MSc_MatrixTest() {}

////////////////////////////////////////////////////////////////////////////////

void MSc_MatrixTest::testConstructor()
{
    MSc_Matrix<2,2> mtrx22;

    QVERIFY( fabs( mtrx22.getItem(0,0) ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22.getItem(0,1) ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22.getItem(1,0) ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22.getItem(1,1) ) < 10.0e-9 );

    MSc_Matrix<2,3> mtrx23;

    QVERIFY( fabs( mtrx23.getItem(0,0) ) < 10.0e-9 );
    QVERIFY( fabs( mtrx23.getItem(0,1) ) < 10.0e-9 );
    QVERIFY( fabs( mtrx23.getItem(0,2) ) < 10.0e-9 );
    QVERIFY( fabs( mtrx23.getItem(1,0) ) < 10.0e-9 );
    QVERIFY( fabs( mtrx23.getItem(1,1) ) < 10.0e-9 );
    QVERIFY( fabs( mtrx23.getItem(1,2) ) < 10.0e-9 );

    mtrx22(0,0) = 1.0;
    mtrx22(0,1) = 2.0;
    mtrx22(1,0) = 3.0;
    mtrx22(1,1) = 4.0;

    MSc_Matrix<2,2> mtrx22_2( mtrx22 );

    QVERIFY( fabs( mtrx22_2.getItem(0,0) - 1.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_2.getItem(0,1) - 2.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_2.getItem(1,0) - 3.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_2.getItem(1,1) - 4.0 ) < 10.0e-9 );

    MSc_Matrix<2,2> mtrx22_3( &mtrx22 );

    QVERIFY( fabs( mtrx22_3.getItem(0,0) - 1.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_3.getItem(0,1) - 2.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_3.getItem(1,0) - 3.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_3.getItem(1,1) - 4.0 ) < 10.0e-9 );
}

////////////////////////////////////////////////////////////////////////////////

void MSc_MatrixTest::testIsValid()
{
    MSc_Matrix<2,2> mtrx22;

    mtrx22(0,0) = 1.0;
    mtrx22(0,1) = 1.0;
    mtrx22(1,0) = 1.0;
    mtrx22(1,1) = 1.0;

    QVERIFY( mtrx22.isValid() );

    mtrx22(0,0) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(0,1) = 1.0;
    mtrx22(1,0) = 1.0;
    mtrx22(1,1) = 1.0;

    QVERIFY( !mtrx22.isValid() );

    mtrx22(0,0) = 1.0;
    mtrx22(0,1) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(1,0) = 1.0;
    mtrx22(1,1) = 1.0;

    QVERIFY( !mtrx22.isValid() );

    mtrx22(0,0) = 1.0;
    mtrx22(0,1) = 1.0;
    mtrx22(1,0) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(1,1) = 1.0;

    QVERIFY( !mtrx22.isValid() );


    mtrx22(0,0) = 1.0;
    mtrx22(0,1) = 1.0;
    mtrx22(1,0) = 1.0;
    mtrx22(1,1) = std::numeric_limits<double>::quiet_NaN();

    QVERIFY( !mtrx22.isValid() );

    mtrx22(0,0) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(0,1) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(1,0) = 1.0;
    mtrx22(1,1) = 1.0;

    QVERIFY( !mtrx22.isValid() );

    mtrx22(0,0) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(0,1) = 1.0;
    mtrx22(1,0) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(1,1) = 1.0;

    QVERIFY( !mtrx22.isValid() );

    mtrx22(0,0) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(0,1) = 1.0;
    mtrx22(1,0) = 1.0;
    mtrx22(1,1) = std::numeric_limits<double>::quiet_NaN();

    QVERIFY( !mtrx22.isValid() );

    mtrx22(0,0) = 1.0;
    mtrx22(0,1) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(1,0) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(1,1) = 1.0;

    QVERIFY( !mtrx22.isValid() );

    mtrx22(0,0) = 1.0;
    mtrx22(0,1) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(1,0) = 1.0;
    mtrx22(1,1) = std::numeric_limits<double>::quiet_NaN();

    QVERIFY( !mtrx22.isValid() );

    mtrx22(0,0) = 1.0;
    mtrx22(0,1) = 1.0;
    mtrx22(1,0) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(1,1) = std::numeric_limits<double>::quiet_NaN();

    QVERIFY( !mtrx22.isValid() );

    mtrx22(0,0) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(0,1) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(1,0) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(1,1) = 1.0;

    QVERIFY( !mtrx22.isValid() );

    mtrx22(0,0) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(0,1) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(1,0) = 1.0;
    mtrx22(1,1) = std::numeric_limits<double>::quiet_NaN();

    QVERIFY( !mtrx22.isValid() );

    mtrx22(0,0) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(0,1) = 1.0;
    mtrx22(1,0) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(1,1) = std::numeric_limits<double>::quiet_NaN();

    QVERIFY( !mtrx22.isValid() );

    mtrx22(0,0) = 1.0;
    mtrx22(0,1) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(1,0) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(1,1) = std::numeric_limits<double>::quiet_NaN();

    QVERIFY( !mtrx22.isValid() );

    mtrx22(0,0) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(0,1) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(1,0) = std::numeric_limits<double>::quiet_NaN();
    mtrx22(1,1) = std::numeric_limits<double>::quiet_NaN();

    QVERIFY( !mtrx22.isValid() );
}

////////////////////////////////////////////////////////////////////////////////

void MSc_MatrixTest::testGetArray()
{
    MSc_Matrix<2,2> mtrx22;

    mtrx22(0,0) = 1.0;
    mtrx22(0,1) = 2.0;
    mtrx22(1,0) = 3.0;
    mtrx22(1,1) = 4.0;

    double array[ 4 ];

    mtrx22.getArray( array );

    QVERIFY( fabs( array[ 0 ] - 1.0 ) < 10.0e-9 );
    QVERIFY( fabs( array[ 1 ] - 2.0 ) < 10.0e-9 );
    QVERIFY( fabs( array[ 2 ] - 3.0 ) < 10.0e-9 );
    QVERIFY( fabs( array[ 3 ] - 4.0 ) < 10.0e-9 );
}

////////////////////////////////////////////////////////////////////////////////

void MSc_MatrixTest::testGetItem()
{
    MSc_Matrix<2,2> mtrx22;

    mtrx22(0,0) = 1.0;
    mtrx22(0,1) = 2.0;
    mtrx22(1,0) = 3.0;
    mtrx22(1,1) = 4.0;

    QVERIFY( fabs( mtrx22.getItem(0,0) - 1.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22.getItem(0,1) - 2.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22.getItem(1,0) - 3.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22.getItem(1,1) - 4.0 ) < 10.0e-9 );

    int exceptionCatchedRow = 0;

    try
    {
        mtrx22.getItem(2,0);
    }
    catch ( MSc_Exception e )
    {
        exceptionCatchedRow = 1;
    }

    QVERIFY( exceptionCatchedRow );

    int exceptionCatchedCol = 0;

    try
    {
        mtrx22.getItem(0,2);
    }
    catch ( MSc_Exception e )
    {
        exceptionCatchedCol = 1;
    }

    QVERIFY( exceptionCatchedCol );
}

////////////////////////////////////////////////////////////////////////////////

void MSc_MatrixTest::testSetArray()
{
    MSc_Matrix<2,2> mtrx22;

    double array[ 4 ] = { 1.0, 2.0, 3.0, 4.0 };

    mtrx22.setArray( array );

    QVERIFY( fabs( mtrx22(0,0) - 1.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22(0,1) - 2.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22(1,0) - 3.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22(1,1) - 4.0 ) < 10.0e-9 );
}

////////////////////////////////////////////////////////////////////////////////

void MSc_MatrixTest::testSetItem()
{
    MSc_Matrix<2,2> mtrx22;

    mtrx22.setItem(0,0, 1.0 );
    mtrx22.setItem(0,1, 2.0 );
    mtrx22.setItem(1,0, 3.0 );
    mtrx22.setItem(1,1, 4.0 );

    QVERIFY( fabs( mtrx22.getItem(0,0) - 1.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22.getItem(0,1) - 2.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22.getItem(1,0) - 3.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22.getItem(1,1) - 4.0 ) < 10.0e-9 );

    int exceptionCatchedRow = 0;

    try
    {
        mtrx22.setItem(2,0, 1.0 );
    }
    catch ( MSc_Exception e )
    {
        exceptionCatchedRow = 1;
    }

    QVERIFY( exceptionCatchedRow );

    int exceptionCatchedCol = 0;

    try
    {
        mtrx22.setItem(0,2, 1.0 );
    }
    catch ( MSc_Exception e )
    {
        exceptionCatchedCol = 1;
    }

    QVERIFY( exceptionCatchedCol );
}

////////////////////////////////////////////////////////////////////////////////

void MSc_MatrixTest::testToString()
{
    MSc_Matrix<2,2> mtrx22;

    mtrx22(0,0) = 1.0;
    mtrx22(0,1) = 2.0;
    mtrx22(1,0) = 3.0;
    mtrx22(1,1) = 4.0;

    std::string out = mtrx22.toString();
    std::string ref;

    std::stringstream ss;

    for ( int i = 0; i < 4; i++ )
    {
        if ( i != 0 ) ss << ",";

        ss << (double)( i + 1 );
    }

    ref = ss.str();

    QVERIFY( !ref.compare( out ) );
}

////////////////////////////////////////////////////////////////////////////////

void MSc_MatrixTest::testOperatorAccess()
{
    MSc_Matrix<2,2> mtrx22;

    mtrx22(0,0) = 1.0;
    mtrx22(0,1) = 2.0;
    mtrx22(1,0) = 3.0;
    mtrx22(1,1) = 4.0;

    QVERIFY( fabs( mtrx22(0,0) - 1.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22(0,1) - 2.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22(1,0) - 3.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22(1,1) - 4.0 ) < 10.0e-9 );

    const MSc_Matrix<2,2> mtrx22_2( mtrx22 );

    QVERIFY( fabs( mtrx22_2(0,0) - 1.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_2(0,1) - 2.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_2(1,0) - 3.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_2(1,1) - 4.0 ) < 10.0e-9 );
}

////////////////////////////////////////////////////////////////////////////////

void MSc_MatrixTest::testOperatorAssign()
{
    MSc_Matrix<2,2> mtrx22_1;

    mtrx22_1(0,0) = 1.0;
    mtrx22_1(0,1) = 2.0;
    mtrx22_1(1,0) = 3.0;
    mtrx22_1(1,1) = 4.0;

    MSc_Matrix<2,2> mtrx22_2;

    mtrx22_2 = mtrx22_1;

    QVERIFY( fabs( mtrx22_2(0,0) - 1.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_2(0,1) - 2.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_2(1,0) - 3.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_2(1,1) - 4.0 ) < 10.0e-9 );
}

////////////////////////////////////////////////////////////////////////////////

void MSc_MatrixTest::testOperatorAddition()
{
    MSc_Matrix<2,2> mtrx22_1;

    mtrx22_1(0,0) = 1.0;
    mtrx22_1(0,1) = 2.0;
    mtrx22_1(1,0) = 3.0;
    mtrx22_1(1,1) = 4.0;

    MSc_Matrix<2,2> mtrx22_2;

    mtrx22_2(0,0) = 1.0;
    mtrx22_2(0,1) = 2.0;
    mtrx22_2(1,0) = 3.0;
    mtrx22_2(1,1) = 4.0;

    MSc_Matrix<2,2> mtrx22_3;

    mtrx22_3 = mtrx22_1 + mtrx22_2;

    QVERIFY( fabs( mtrx22_3(0,0) - 2.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_3(0,1) - 4.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_3(1,0) - 6.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_3(1,1) - 8.0 ) < 10.0e-9 );
}

////////////////////////////////////////////////////////////////////////////////

void MSc_MatrixTest::testOperatorSubstraction()
{
    MSc_Matrix<2,2> mtrx22_1;

    mtrx22_1(0,0) = 1.0;
    mtrx22_1(0,1) = 2.0;
    mtrx22_1(1,0) = 3.0;
    mtrx22_1(1,1) = 4.0;

    MSc_Matrix<2,2> mtrx22_2;

    mtrx22_2(0,0) = 1.0;
    mtrx22_2(0,1) = 2.0;
    mtrx22_2(1,0) = 3.0;
    mtrx22_2(1,1) = 4.0;

    MSc_Matrix<2,2> mtrx22_3;

    mtrx22_3 = mtrx22_1 - mtrx22_2;

    QVERIFY( fabs( mtrx22_3(0,0) ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_3(0,1) ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_3(1,0) ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_3(1,1) ) < 10.0e-9 );
}

////////////////////////////////////////////////////////////////////////////////

void MSc_MatrixTest::testOperatorMultiplication()
{
    MSc_Matrix<2,2> mtrx22_1;

    mtrx22_1(0,0) = 1.0;
    mtrx22_1(0,1) = 2.0;
    mtrx22_1(1,0) = 3.0;
    mtrx22_1(1,1) = 4.0;

    MSc_Matrix<2,2> mtrx22_2;

    mtrx22_2 = mtrx22_1 * 2.0;

    QVERIFY( fabs( mtrx22_2(0,0) - 2.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_2(0,1) - 4.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_2(1,0) - 6.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_2(1,1) - 8.0 ) < 10.0e-9 );

    mtrx22_2(0,0) = 8.0;
    mtrx22_2(0,1) = 7.0;
    mtrx22_2(1,0) = 6.0;
    mtrx22_2(1,1) = 5.0;

    MSc_Matrix<2,2> mtrx22_3;

    mtrx22_3 = mtrx22_1 * mtrx22_2;

    QVERIFY( fabs( mtrx22_3(0,0) - 20.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_3(0,1) - 17.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_3(1,0) - 48.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_3(1,1) - 41.0 ) < 10.0e-9 );

    mtrx22_3 = mtrx22_2 * mtrx22_1;

    QVERIFY( fabs( mtrx22_3(0,0) - 29.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_3(0,1) - 44.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_3(1,0) - 21.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_3(1,1) - 32.0 ) < 10.0e-9 );

    MSc_Matrix<3,3> mtrx33_1;
    MSc_Matrix<3,3> mtrx33_2;
    MSc_Matrix<3,3> mtrx33_3;

    mtrx33_1(0,0) =  1.0;
    mtrx33_1(0,1) =  2.0;
    mtrx33_1(0,2) =  3.0;
    mtrx33_1(1,0) =  4.0;
    mtrx33_1(1,1) =  5.0;
    mtrx33_1(1,2) =  6.0;
    mtrx33_1(2,0) =  7.0;
    mtrx33_1(2,1) =  8.0;
    mtrx33_1(2,2) =  9.0;

    mtrx33_2(0,0) =  9.0;
    mtrx33_2(0,1) =  8.0;
    mtrx33_2(0,2) =  7.0;
    mtrx33_2(1,0) =  6.0;
    mtrx33_2(1,1) =  5.0;
    mtrx33_2(1,2) =  4.0;
    mtrx33_2(2,0) =  3.0;
    mtrx33_2(2,1) =  2.0;
    mtrx33_2(2,2) =  1.0;

    mtrx33_3 = mtrx33_1 * mtrx33_2;

    QVERIFY( fabs( mtrx33_3(0,0) -  30.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx33_3(0,1) -  24.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx33_3(0,2) -  18.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx33_3(1,0) -  84.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx33_3(1,1) -  69.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx33_3(1,2) -  54.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx33_3(2,0) - 138.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx33_3(2,1) - 114.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx33_3(2,2) -  90.0 ) < 10.0e-9 );

    MSc_Vector<2> vect_1;

    vect_1(0) = 11.0;
    vect_1(1) = 22.0;

    MSc_Vector<2> vect_2;

    vect_2 = mtrx22_1 * vect_1;

    QVERIFY( fabs( vect_2(0) -  55.0 ) < 10.0e-9 );
    QVERIFY( fabs( vect_2(1) - 121.0 ) < 10.0e-9 );

    vect_2 = mtrx22_2 * vect_1;

    QVERIFY( fabs( vect_2(0) - 242.0 ) < 10.0e-9 );
    QVERIFY( fabs( vect_2(1) - 176.0 ) < 10.0e-9 );

    MSc_Matrix<3,2> mtrx32_1;

    mtrx32_1(0,0) =  3.0;
    mtrx32_1(0,1) =  1.0;
    mtrx32_1(1,0) =  2.0;
    mtrx32_1(1,1) =  1.0;
    mtrx32_1(2,0) =  1.0;
    mtrx32_1(2,1) =  0.0;

    MSc_Vector<3> vect_3;

    vect_3 = mtrx32_1 * vect_1;

    QVERIFY( fabs( vect_3(0) - 55.0 ) < 10.0e-9 );
    QVERIFY( fabs( vect_3(1) - 44.0 ) < 10.0e-9 );
    QVERIFY( fabs( vect_3(2) - 11.0 ) < 10.0e-9 );
}

////////////////////////////////////////////////////////////////////////////////

void MSc_MatrixTest::testOperatorDivision()
{
    MSc_Matrix<2,2> mtrx22_1;

    mtrx22_1(0,0) = 2.0;
    mtrx22_1(0,1) = 4.0;
    mtrx22_1(1,0) = 6.0;
    mtrx22_1(1,1) = 8.0;

    MSc_Matrix<2,2> mtrx22_2;

    mtrx22_2 = mtrx22_1 / 2.0;

    QVERIFY( fabs( mtrx22_2(0,0) - 1.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_2(0,1) - 2.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_2(1,0) - 3.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_2(1,1) - 4.0 ) < 10.0e-9 );
}

////////////////////////////////////////////////////////////////////////////////

void MSc_MatrixTest::testOperatorUnaryAddition()
{
    MSc_Matrix<2,2> mtrx22_1;

    mtrx22_1(0,0) = 1.0;
    mtrx22_1(0,1) = 2.0;
    mtrx22_1(1,0) = 3.0;
    mtrx22_1(1,1) = 4.0;

    MSc_Matrix<2,2> mtrx22_2;

    mtrx22_2(0,0) = 4.0;
    mtrx22_2(0,1) = 3.0;
    mtrx22_2(1,0) = 2.0;
    mtrx22_2(1,1) = 1.0;

    mtrx22_1 += mtrx22_2;

    QVERIFY( fabs( mtrx22_1(0,0) - 5.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_1(0,1) - 5.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_1(1,0) - 5.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_1(1,1) - 5.0 ) < 10.0e-9 );
}

////////////////////////////////////////////////////////////////////////////////

void MSc_MatrixTest::testOperatorUnarySubstraction()
{
    MSc_Matrix<2,2> mtrx22_1;

    mtrx22_1(0,0) = 1.0;
    mtrx22_1(0,1) = 2.0;
    mtrx22_1(1,0) = 3.0;
    mtrx22_1(1,1) = 4.0;

    MSc_Matrix<2,2> mtrx22_2;

    mtrx22_2(0,0) = 4.0;
    mtrx22_2(0,1) = 3.0;
    mtrx22_2(1,0) = 2.0;
    mtrx22_2(1,1) = 1.0;

    mtrx22_1 -= mtrx22_2;

    QVERIFY( fabs( mtrx22_1(0,0) + 3.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_1(0,1) + 1.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_1(1,0) - 1.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_1(1,1) - 3.0 ) < 10.0e-9 );
}

////////////////////////////////////////////////////////////////////////////////

void MSc_MatrixTest::testOperatorUnaryMultiplication()
{
    MSc_Matrix<2,2> mtrx22_1;

    mtrx22_1(0,0) = 1.0;
    mtrx22_1(0,1) = 2.0;
    mtrx22_1(1,0) = 3.0;
    mtrx22_1(1,1) = 4.0;

    mtrx22_1 *= 2.0;

    QVERIFY( fabs( mtrx22_1(0,0) - 2.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_1(0,1) - 4.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_1(1,0) - 6.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_1(1,1) - 8.0 ) < 10.0e-9 );
}

////////////////////////////////////////////////////////////////////////////////

void MSc_MatrixTest::testOperatorUnaryDivision()
{
    MSc_Matrix<2,2> mtrx22_1;

    mtrx22_1(0,0) = 2.0;
    mtrx22_1(0,1) = 4.0;
    mtrx22_1(1,0) = 6.0;
    mtrx22_1(1,1) = 8.0;

    mtrx22_1 /= 2.0;

    QVERIFY( fabs( mtrx22_1(0,0) - 1.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_1(0,1) - 2.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_1(1,0) - 3.0 ) < 10.0e-9 );
    QVERIFY( fabs( mtrx22_1(1,1) - 4.0 ) < 10.0e-9 );
}

////////////////////////////////////////////////////////////////////////////////

void MSc_MatrixTest::testOperatorEquality()
{
    MSc_Matrix<2,2> mtrx22_1;

    mtrx22_1(0,0) = 1.0;
    mtrx22_1(0,1) = 2.0;
    mtrx22_1(1,0) = 3.0;
    mtrx22_1(1,1) = 4.0;

    MSc_Matrix<2,2> mtrx22_2;

    mtrx22_2(0,0) = 1.0;
    mtrx22_2(0,1) = 2.0;
    mtrx22_2(1,0) = 3.0;
    mtrx22_2(1,1) = 4.0;

    QVERIFY( mtrx22_1 == mtrx22_2 );

    mtrx22_2(0,0) = 0.0;
    mtrx22_2(0,1) = 2.0;
    mtrx22_2(1,0) = 3.0;
    mtrx22_2(1,1) = 4.0;

    QVERIFY( !( mtrx22_1 == mtrx22_2 ) );

    mtrx22_2(0,0) = 1.0;
    mtrx22_2(0,1) = 0.0;
    mtrx22_2(1,0) = 3.0;
    mtrx22_2(1,1) = 4.0;

    QVERIFY( !( mtrx22_1 == mtrx22_2 ) );

    mtrx22_2(0,0) = 1.0;
    mtrx22_2(0,1) = 2.0;
    mtrx22_2(1,0) = 0.0;
    mtrx22_2(1,1) = 4.0;

    QVERIFY( !( mtrx22_1 == mtrx22_2 ) );

    mtrx22_2(0,0) = 1.0;
    mtrx22_2(0,1) = 2.0;
    mtrx22_2(1,0) = 3.0;
    mtrx22_2(1,1) = 0.0;

    QVERIFY( !( mtrx22_1 == mtrx22_2 ) );

    mtrx22_2(0,0) = 0.0;
    mtrx22_2(0,1) = 0.0;
    mtrx22_2(1,0) = 3.0;
    mtrx22_2(1,1) = 4.0;

    QVERIFY( !( mtrx22_1 == mtrx22_2 ) );

    mtrx22_2(0,0) = 0.0;
    mtrx22_2(0,1) = 2.0;
    mtrx22_2(1,0) = 0.0;
    mtrx22_2(1,1) = 4.0;

    QVERIFY( !( mtrx22_1 == mtrx22_2 ) );

    mtrx22_2(0,0) = 0.0;
    mtrx22_2(0,1) = 2.0;
    mtrx22_2(1,0) = 3.0;
    mtrx22_2(1,1) = 0.0;

    QVERIFY( !( mtrx22_1 == mtrx22_2 ) );

    mtrx22_2(0,0) = 1.0;
    mtrx22_2(0,1) = 0.0;
    mtrx22_2(1,0) = 0.0;
    mtrx22_2(1,1) = 4.0;

    QVERIFY( !( mtrx22_1 == mtrx22_2 ) );

    mtrx22_2(0,0) = 1.0;
    mtrx22_2(0,1) = 0.0;
    mtrx22_2(1,0) = 3.0;
    mtrx22_2(1,1) = 0.0;

    QVERIFY( !( mtrx22_1 == mtrx22_2 ) );

    mtrx22_2(0,0) = 1.0;
    mtrx22_2(0,1) = 2.0;
    mtrx22_2(1,0) = 0.0;
    mtrx22_2(1,1) = 0.0;

    QVERIFY( !( mtrx22_1 == mtrx22_2 ) );

    mtrx22_2(0,0) = 0.0;
    mtrx22_2(0,1) = 0.0;
    mtrx22_2(1,0) = 0.0;
    mtrx22_2(1,1) = 4.0;

    QVERIFY( !( mtrx22_1 == mtrx22_2 ) );

    mtrx22_2(0,0) = 0.0;
    mtrx22_2(0,1) = 0.0;
    mtrx22_2(1,0) = 3.0;
    mtrx22_2(1,1) = 0.0;

    QVERIFY( !( mtrx22_1 == mtrx22_2 ) );

    mtrx22_2(0,0) = 1.0;
    mtrx22_2(0,1) = 0.0;
    mtrx22_2(1,0) = 0.0;
    mtrx22_2(1,1) = 0.0;

    QVERIFY( !( mtrx22_1 == mtrx22_2 ) );

    mtrx22_2(0,0) = 0.0;
    mtrx22_2(0,1) = 0.0;
    mtrx22_2(1,0) = 0.0;
    mtrx22_2(1,1) = 0.0;

    QVERIFY( !( mtrx22_1 == mtrx22_2 ) );
}

////////////////////////////////////////////////////////////////////////////////

void MSc_MatrixTest::testOperatorInequality()
{
    MSc_Matrix<2,2> mtrx22_1;

    mtrx22_1(0,0) = 1.0;
    mtrx22_1(0,1) = 2.0;
    mtrx22_1(1,0) = 3.0;
    mtrx22_1(1,1) = 4.0;

    MSc_Matrix<2,2> mtrx22_2;

    mtrx22_2(0,0) = 1.0;
    mtrx22_2(0,1) = 2.0;
    mtrx22_2(1,0) = 3.0;
    mtrx22_2(1,1) = 4.0;

    QVERIFY( !( mtrx22_1 != mtrx22_2 ) );

    mtrx22_2(0,0) = 0.0;
    mtrx22_2(0,1) = 2.0;
    mtrx22_2(1,0) = 3.0;
    mtrx22_2(1,1) = 4.0;

    QVERIFY( mtrx22_1 != mtrx22_2 );

    mtrx22_2(0,0) = 1.0;
    mtrx22_2(0,1) = 0.0;
    mtrx22_2(1,0) = 3.0;
    mtrx22_2(1,1) = 4.0;

    QVERIFY( mtrx22_1 != mtrx22_2 );

    mtrx22_2(0,0) = 1.0;
    mtrx22_2(0,1) = 2.0;
    mtrx22_2(1,0) = 0.0;
    mtrx22_2(1,1) = 4.0;

    QVERIFY( mtrx22_1 != mtrx22_2 );

    mtrx22_2(0,0) = 1.0;
    mtrx22_2(0,1) = 2.0;
    mtrx22_2(1,0) = 3.0;
    mtrx22_2(1,1) = 0.0;

    QVERIFY( mtrx22_1 != mtrx22_2 );

    mtrx22_2(0,0) = 0.0;
    mtrx22_2(0,1) = 0.0;
    mtrx22_2(1,0) = 3.0;
    mtrx22_2(1,1) = 4.0;

    QVERIFY( mtrx22_1 != mtrx22_2 );

    mtrx22_2(0,0) = 0.0;
    mtrx22_2(0,1) = 2.0;
    mtrx22_2(1,0) = 0.0;
    mtrx22_2(1,1) = 4.0;

    QVERIFY( mtrx22_1 != mtrx22_2 );

    mtrx22_2(0,0) = 0.0;
    mtrx22_2(0,1) = 2.0;
    mtrx22_2(1,0) = 3.0;
    mtrx22_2(1,1) = 0.0;

    QVERIFY( mtrx22_1 != mtrx22_2 );

    mtrx22_2(0,0) = 1.0;
    mtrx22_2(0,1) = 0.0;
    mtrx22_2(1,0) = 0.0;
    mtrx22_2(1,1) = 4.0;

    QVERIFY( mtrx22_1 != mtrx22_2 );

    mtrx22_2(0,0) = 1.0;
    mtrx22_2(0,1) = 0.0;
    mtrx22_2(1,0) = 3.0;
    mtrx22_2(1,1) = 0.0;

    QVERIFY( mtrx22_1 != mtrx22_2 );

    mtrx22_2(0,0) = 1.0;
    mtrx22_2(0,1) = 2.0;
    mtrx22_2(1,0) = 0.0;
    mtrx22_2(1,1) = 0.0;

    QVERIFY( mtrx22_1 != mtrx22_2 );

    mtrx22_2(0,0) = 0.0;
    mtrx22_2(0,1) = 0.0;
    mtrx22_2(1,0) = 0.0;
    mtrx22_2(1,1) = 4.0;

    QVERIFY( mtrx22_1 != mtrx22_2 );

    mtrx22_2(0,0) = 0.0;
    mtrx22_2(0,1) = 0.0;
    mtrx22_2(1,0) = 3.0;
    mtrx22_2(1,1) = 0.0;

    QVERIFY( mtrx22_1 != mtrx22_2 );

    mtrx22_2(0,0) = 1.0;
    mtrx22_2(0,1) = 0.0;
    mtrx22_2(1,0) = 0.0;
    mtrx22_2(1,1) = 0.0;

    QVERIFY( mtrx22_1 != mtrx22_2 );

    mtrx22_2(0,0) = 0.0;
    mtrx22_2(0,1) = 0.0;
    mtrx22_2(1,0) = 0.0;
    mtrx22_2(1,1) = 0.0;

    QVERIFY( mtrx22_1 != mtrx22_2 );
}

////////////////////////////////////////////////////////////////////////////////

QTEST_APPLESS_MAIN(MSc_MatrixTest)

////////////////////////////////////////////////////////////////////////////////

#include "tst_msc_matrixtest.moc"
